package org.xserver.component.core.dispatch;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.xserver.component.core.XServerHttpContextAttachment;
import org.xserver.component.exception.FilterProcessError;
import org.xserver.component.extension.filter.ContextFilter;
import org.xserver.component.extension.filter.DefaultContextFilterManager;
import org.xserver.component.extension.filter.FilterType;

@Component
public class RequestDispatchFilter {

	private static final Logger logger = LoggerFactory.getLogger(RequestDispatchFilter.class);

	@Resource
	private DefaultContextFilterManager filterContextFactory;

	/**
	 * the request go to business logic process, it should flow past matches
	 * filter(s). If there is no filter accept the request, the request will
	 * pass to next process(business logic). If there are some filters, matched
	 * filters need process the request in order. When one filter process error,
	 * the rest of filter and business logic should not receive the request.
	 * 
	 * @param attachment
	 * @throws Exception
	 */
	public void filterDispatch(XServerHttpContextAttachment attachment, FilterType filterType) throws Exception {
		String requestPath = attachment.getRequest().getPath();

		if (filterContextFactory == null) {
			return;
		}

		List<ContextFilter> filterChain = new ArrayList<ContextFilter>();
		if (filterType.equals(FilterType.BEFORE)) {
			filterChain = filterContextFactory.getBeforeFilterContext().get(requestPath);
		} else if (filterType.equals(FilterType.RETURN)) {
			filterChain = filterContextFactory.getReturnFilterContext().get(requestPath);
		}

		if (filterChain == null) {
			return;
		}

		for (ContextFilter filter : filterChain) {
			logger.info("Enter filter[{}]", filter);
			try {
				filter.contextProcess(attachment);
			} catch (FilterProcessError e) {
				logger.error("request[" + requestPath + "] go throught filter[" + e.getFilterName() + "] error", e);
				if (filter.isExceptionGoNext()) {
					continue;
				}

				throw e;
			}
		}
	}
}
